//
//  BaseCa.swift
//  MobileRTCSwiftSample
//
//  Created by zhangheng on 2019/6/13.
//  Copyright © 2019 Zoom Video Communications, Inc. All rights reserved.
//

import Foundation

fileprivate enum MapError: Error {
    case jsonToModelFail    //json转model失败
    case jsonToDataFail     //json转data失败
    case dictToJsonFail     //字典转json失败
    case jsonToArrFail      //json转数组失败
    case modelToJsonFail    //model转json失败
}

protocol Mappable: Codable {
    func modelMapFinnished()
    mutating func structMapFinished()
}
extension Mappable{
    func modelMapFinnished(){}
    mutating func structMapFinished(){}
    
    //模型转字典
    func reflectTodict() -> [String:Any] {
        let mirro = Mirror.init(reflecting: self)
        var dict = [String:Any]()
        for case let (key?,value) in mirro.children {
            dict[key] = value
        }
        return dict
    }
    //字典转模型
    static func mapFromDic<T:Mappable>(_ dict:[String:Any],_ type:T.Type) throws -> T {
        guard let JSONString = dict.toJsonString() else {
            print("MapError.dictToJsonFail")
            throw MapError.dictToJsonFail
        }
        guard let jsonData = JSONString.data(using: .utf8) else {
            print(MapError.jsonToDataFail)
            throw MapError.jsonToDataFail
        }
        let decoder = JSONDecoder()
        if  let obj = try? decoder.decode(type, from: jsonData) {
            var vobj = obj
            let mirro = Mirror.init(reflecting: vobj)
            if mirro.displayStyle == Mirror.DisplayStyle.struct {
                vobj.structMapFinished()
            }
            if mirro.displayStyle == Mirror.DisplayStyle.class {
                vobj.modelMapFinnished()
            }
            return vobj
        }
        print(MapError.jsonToModelFail)
        throw MapError.jsonToModelFail
    }
    //Json转模型
    static func mapFromJSon<T:Mappable>(_ jsonSting:String,_ type:T.Type) throws -> T {
        guard let jsonData = jsonSting.data(using: .utf8) else {
            print(MapError.jsonToDataFail)
            throw MapError.jsonToDataFail
        }
        let decoder = JSONDecoder()
        if let obj = try? decoder.decode(type, from: jsonData) {
            return obj
        }
        print(MapError.jsonToModelFail)
        throw MapError.jsonToModelFail
    }
    //model转json 字符串
    func toJSonSting() -> String {
        if let str = self.reflectTodict().toJsonString() {
            return str
        }
        return ""
    }
}
extension Dictionary {
    func toJsonString() -> String? {
        if !JSONSerialization.isValidJSONObject(self) {
            print("dict 转 json 失败")
            return nil
        }
        if let newData:Data = try? JSONSerialization.data(withJSONObject: self, options: []) {
            let JSONString = NSString.init(data: newData, encoding: String.Encoding.utf8.rawValue)
            return JSONString as String? ?? nil
        }
        print("dict 转 json 失败")
        return nil
    }
}
extension Array {
    func toJsonString() -> String? {
        if !JSONSerialization.isValidJSONObject(self) {
            print("dict转json失败")
            return nil
        }
        if let newData : Data = try? JSONSerialization.data(withJSONObject: self, options: []) {
            let JSONString = NSString(data:newData as Data,encoding: String.Encoding.utf8.rawValue)
            return JSONString as String? ?? nil
        }
        print("dict转json失败")
        return nil
    }
    static func mapFromJson<T:Decodable>(_ jsonString:String,_ type:[T].Type) throws -> Array<T> {
        guard let JSonData = jsonString.data(using: .utf8) else {
            print(MapError.jsonToDataFail)
            throw MapError.jsonToDataFail
        }
        let decoder = JSONDecoder()
        if let obj = try? decoder.decode(type, from: JSonData) {
            return obj
        }
        print(MapError.jsonToArrFail)
        throw MapError.jsonToArrFail
    }
}
extension String {
    func toDict() -> [String:Any]? {
        guard let jsonData:Data = self.data(using: .utf8) else {
            print("json转dict失败")
            return nil
        }
        if let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) {
            return dict as? [String : Any] ?? ["":""]
        }
        print("json转dict失败")
        return nil
    }
    
    func toDicObjc() -> [String:AnyObject]? {
        guard let jsonData:Data = self.data(using: .utf8) else {
            print("json转dict失败")
            return nil
        }
        if let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) {
            return dict as? [String : AnyObject]
        }
        print("json转dict失败")
        return nil
    }
}
